package org.jeecg.modules.rental.util;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.jeecg.common.desensitization.enums.SensitiveEnum;
import org.jeecg.common.desensitization.util.SensitiveInfoUtil;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.app.api.AppApi;
import org.jeecg.modules.app.entity.AppClient;
import org.jeecg.modules.app.entity.AppUpgrade;
import org.jeecg.modules.rental.vo.WxSessionVO;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.security.MessageDigest;
import java.util.Formatter;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 校验服务器所保存的登录态 session_key 是否合法。为了保持 session_key 私密性，接口不明文传输 session_key，
 * 而是通过校验登录态签名完成。现在我们把session_key 给到了小程序端，后续优化看下面的链接
 * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/checkSessionKey.html
 */
@Component
@RequiredArgsConstructor
public class WxAuthorizationUtil {

    private final static String code2session_URL = "https://api.weixin.qq.com/sns/jscode2session";
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    private static final String JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";
    private final static String CACHE_KEY = "app:wx:appSecret::";

    private final RedisUtil redisUtil;

    private final AppApi appApi;

    public String wxAppSecret(String appId){
        String appSecret = "";
        String appSecretKey = CACHE_KEY +  appId;
        if (redisUtil.hasKey(appSecretKey)) {
            String appSecrettext = (String) redisUtil.get(appSecretKey);
            //解密
            appSecret = SensitiveInfoUtil.getDecodeData(appSecrettext);
        }else{
            AppClient appClient = appApi.queryByAppId(appId);
            if(oConvertUtils.isNotEmpty(appClient) && oConvertUtils.isNotEmpty(appClient.getAppSecret())){
                //解密
                appSecret = SensitiveInfoUtil.getDecodeData(appClient.getAppSecret());;
                //保存到redis
                redisUtil.set(appSecretKey, appClient.getAppSecret());
            }
        }
        return appSecret;
    }

    /**
     * 获取微信Session
     * @param code
     * @return
     */
    public WxSessionVO code2session(String appId, String code) {
        String appSecret = this.wxAppSecret(appId);
        WxSessionVO wxSession = new WxSessionVO();
        String result = HttpUtil.get(code2session_URL,
                "appid=" + appId + //小程序APPID
                        "&secret="+ appSecret + //小程序秘钥
                        "&js_code="+ code + //前端传来的code
                        "&grant_type=authorization_code");
        JSONObject jsonObject = JSONObject.parseObject(result);
        if (jsonObject.containsKey("errcode")) {
            throw new JeecgBootException("code无效");
        }
        String openId = jsonObject.get("openid").toString();
        if (null == openId || openId.isEmpty()) {
            throw new JeecgBootException("openid为空");
        }
        wxSession.setOpenid(openId);
        String sessionKey = jsonObject.get("session_key").toString();
        if (null == sessionKey || sessionKey.isEmpty()) {
            throw new JeecgBootException("session_key为空");
        }
        wxSession.setSessionKey(sessionKey);
        return wxSession;
    }



    public static String generateSignature(String jsapiTicket, String nonceStr, String timestamp, String url) throws Exception {
        SortedMap<String, String> params = new TreeMap<>();
        params.put("jsapi_ticket", jsapiTicket);
        params.put("noncestr", nonceStr);
        params.put("timestamp", timestamp);
        params.put("url", url);

        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        sb.deleteCharAt(sb.length() - 1); // 删除最后一个 '&'

        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(sb.toString().getBytes("UTF-8"));

        return byteToHex(crypt.digest());
    }

    public static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        return formatter.toString();
    }


    /**
     * 获取 Access Token
     */
    public static String getAccessToken(String appId, String appSecret) {
        try {
            RestTemplate restTemplate = new RestTemplate();
            String url = String.format(ACCESS_TOKEN_URL, appId, appSecret);
            String response = restTemplate.getForObject(url, String.class);

            Map<String, Object> result = new ObjectMapper().readValue(response, Map.class);
            if (result.containsKey("access_token")) {
                return (String) result.get("access_token");
            } else {
                throw new RuntimeException("获取 access_token 失败: " + result.get("errmsg"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    public static String getJsapiTicket(String accessToken) {
        try {
            RestTemplate restTemplate = new RestTemplate();
            String url = String.format(JSAPI_TICKET_URL, accessToken);
            String response = restTemplate.getForObject(url, String.class);
            Map<String, Object> result = new ObjectMapper().readValue(response, Map.class);
            return (String) result.get("ticket");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }





}
